package org.ktm.utils;

import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.CRC32;
import org.ktm.exception.KTMRuntimeException;

public class CRCCalculator {

    private StringBuffer            data       = new StringBuffer();
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMdHms");

    public CRCCalculator() {
    }

    public void add(Object object) {
        if (object == null) {
            object = Boolean.FALSE;
        }
        if (object instanceof BigDecimal) {
            add(((BigDecimal) object).doubleValue());
        } else if (object instanceof Float) {
            add(((Float) object).floatValue());
        } else if (object instanceof Double) {
            add(((Double) object).doubleValue());
        } else if (object instanceof Boolean) {
            add(((Boolean) object).booleanValue());
        } else if (object instanceof Date) {
            data.append(dateFormat.format((Date) object));
        } else if (object instanceof byte[]) {
            CRC32 crc = new CRC32();
            crc.update((byte[]) object);
            data.append(crc.getValue());
        } else {
            data.append(object.toString());
        }
    }

    public void add(int val) {
        data.append(val);
    }

    public void add(long val) {
        data.append(val);
    }

    public void add(short val) {
        data.append(val);
    }

    public void add(float val) {
        data.append(new DecimalFormat("###########0.0000").format(val));
    }

    public void add(double val) {
        data.append(new DecimalFormat("###########0.000000").format(val));
    }

    public void add(boolean val) {
        if (val) {
            data.append("T");
        } else {
            data.append("F");
        }
    }

    public void add(byte val) {
        data.append(val);
    }

    public void add(char val) {
        data.append(val);
    }

    public long getCRC() {
        // Convert string to byte array using UTF8 encoding:
        Charset charSet = Charset.forName("UTF8");
        if (charSet == null) { throw new KTMRuntimeException("Cannot get UTF8 character set for CRC-32 calculation"); }
        ByteBuffer buf = charSet.encode(data.toString());
        byte[] bytes = new byte[buf.remaining()];
        buf.get(bytes);

        // Calculate the actual CRC.
        CRC32 crc = new CRC32();
        crc.update(bytes);
        return crc.getValue();
    }
}
